package msgs

import (
	"encoding/binary"
	"ospf/common"
	"ospf/tables"
)

type LSType uint8

const (
	RouterLSAType LSType = iota + 1
	NetworkLSAType
	SummarryLSAType
	OthersType

	routerLSALen  = 48
	networkLSALen = 28
)

type LinkStateAdvertisement interface {
	Len() int
	GetHeader() *LSAHeader
	Serialize() ([]byte, error)
	Deserialize([]byte) error
}

type RouterLSA struct {
	Header LSAHeader
	// 大多用于表明该路由器的身份，只有高8位有效果，低8位用于占位
	Flags uint16
	// 本条LSA中包含的link数量
	NumberOfLinks uint16
	Links         []Link
}

// ExtractInfo 从RouterLSA中提取链路信息和节点信息
func (r *RouterLSA) ExtractInfo() (nodes []*tables.Node, src common.ID, edges []common.ID, weights []int) {
	src = r.Header.AdvertisingRouter
	nodes = append(nodes, &tables.Node{
		ID:  src,
		Ips: []common.ID{r.Header.LinkStateID},
	})
	edges = make([]common.ID, r.NumberOfLinks)
	weights = make([]int, r.NumberOfLinks)
	for i, l := range r.Links {
		edges[i] = l.LinkID
		weights[i] = int(l.Metric)
		nodes = append(nodes, &tables.Node{
			ID:  l.LinkID,
			Ips: []common.ID{l.LinkData},
		})

	}
	return
}

func GenRouterLSA(lsDb *tables.OspfLSDB, ip common.ID) (RouterLSA, error) {
	routerLSA := RouterLSA{
		Header:        *GenLSAHeader(RouterLSAType, ip, lsDb.RouterID),
		NumberOfLinks: 0,
		Links:         GenLinks(lsDb),
	}
	pl := len(routerLSA.Links)
	routerLSA.NumberOfLinks = uint16(pl)
	pl = pl*12 + lsaHeaderLen + 4
	routerLSA.Header.Length = uint16(pl)
	tData := make([]byte, pl)
	tData, err := routerLSA.Serialize()
	if err != nil {
		return RouterLSA{}, err
	}
	routerLSA.Header.Checksum = CalculateCheckSum(tData)
	return routerLSA, nil
}

type Link struct {
	// 邻居的router-id
	LinkID common.ID
	// 邻居的ip
	LinkData        common.ID
	LinkType        uint8
	NumberOfMetrics uint8
	Metric          uint16
}

// GenLinks 根据邻居表中的条目，生成对应的链路发送包
func GenLinks(lsDb *tables.OspfLSDB) []Link {
	neighbors := lsDb.NeighT.GetNeighbors()
	links := make([]Link, len(neighbors))
	for i, neighbor := range neighbors {
		links[i] = Link{
			LinkID:          neighbor.GetRouterId(),
			LinkData:        common.CIDR(neighbor.GetIP()),
			LinkType:        2,
			NumberOfMetrics: 0,
			Metric:          10,
		}
	}
	return links
}

// Serialize 将 RouterLSA 对象的信息转化为比特流并存入data中
func (r *RouterLSA) Serialize() ([]byte, error) {
	data := make([]byte, r.Header.Length)
	err := r.Header.Serialize(data[:lsaHeaderLen])
	if err != nil {
		return nil, common.ErrSerialize("fail to serialize router-lsa header.")
	}
	binary.BigEndian.PutUint16(data[lsaHeaderLen:lsaHeaderLen+2], r.Flags)
	binary.BigEndian.PutUint16(data[lsaHeaderLen+2:lsaHeaderLen+4], r.NumberOfLinks)
	idx := lsaHeaderLen + 4
	for _, l := range r.Links {
		copy(data[idx:idx+4], l.LinkID[:])
		copy(data[idx+4:idx+8], l.LinkData[:])
		data[idx+8] = l.LinkType
		data[idx+9] = l.NumberOfMetrics
		binary.BigEndian.PutUint16(data[idx+10:idx+12], l.Metric)
	}
	return data, nil
}

// Deserialize 从data读取数据并映射到 RouterLSA 中，需要处理包含header和body的所有信息
func (r *RouterLSA) Deserialize(data []byte) error {
	r.Header = LSAHeader{}
	err := r.Header.Deserialize(data[:lsaHeaderLen])
	if err != nil {
		return err
	}

	r.Flags = binary.BigEndian.Uint16(data[lsaHeaderLen : lsaHeaderLen+2])
	r.NumberOfLinks = binary.BigEndian.Uint16(data[lsaHeaderLen+2 : lsaHeaderLen+4])
	r.Links = make([]Link, r.NumberOfLinks)
	idx := lsaHeaderLen + 4
	for i := range r.Links {
		r.Links[i].LinkID = common.ID(data[idx : idx+4])
		r.Links[i].LinkData = common.ID(data[idx+4 : idx+8])
		r.Links[i].LinkType = data[idx+8]
		r.Links[i].NumberOfMetrics = data[idx+9]
		r.Links[i].Metric = binary.BigEndian.Uint16(data[idx+10 : idx+12])
		idx += 12
	}
	return nil
}

func (r *RouterLSA) Len() int {
	return int(r.Header.Length)
}

func (r *RouterLSA) GetHeader() *LSAHeader {
	return &r.Header
}
